package com.xb.xbpm.utils;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLContext;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URISyntaxException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Map;

public class HttpClientUtil {

    private static PoolingHttpClientConnectionManager cm;
    private static String EMPTY_STR = "";
    private static String UTF_8 = "UTF-8";
    private static RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(5000).setConnectionRequestTimeout(1000).setSocketTimeout(5000).build();

    static {
        if (cm == null) {
            LayeredConnectionSocketFactory sslsf = null;
            try {
                sslsf = new SSLConnectionSocketFactory(SSLContext.getDefault());
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
            Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create()
                    .register("https", sslsf)
                    .register("http", new PlainConnectionSocketFactory())
                    .build();
            cm =new PoolingHttpClientConnectionManager(socketFactoryRegistry);
            cm.setMaxTotal(200);
            cm.setDefaultMaxPerRoute(20);
        }
    }

    /**
     * 通过连接池获取HttpClient
     *
     * @return
     */
    private static CloseableHttpClient getHttpClient() {
        return HttpClients.custom().setConnectionManager(cm).build();
    }


    /**
     *
     * @param url
     * @return
     */
    public static String doGet(String url) {
        HttpGet httpGet = new HttpGet(url);
        return getResult(httpGet);
    }
    public static String image(String url) {
        HttpGet httpGet = new HttpGet(url);
        return getResult2(httpGet);
    }

    public static String doGet(String url, Map<?, ?> params) throws URISyntaxException {
        URIBuilder ub = new URIBuilder();
        ub.setPath(url);

        ArrayList<NameValuePair> pairs = covertParams2NVPS(params);
        ub.setParameters(pairs);

        HttpGet httpGet = new HttpGet(ub.build());
        return getResult(httpGet);
    }

    public static String doGet(String url, Map<?, ?> headers, Map<?, ?> params) throws URISyntaxException {
        URIBuilder ub = new URIBuilder();
        ub.setPath(url);

        ArrayList<NameValuePair> pairs = covertParams2NVPS(params);
        ub.setParameters(pairs);

        HttpGet httpGet = new HttpGet(ub.build());
        for (Map.Entry<?, ?> param : headers.entrySet()) {
            httpGet.addHeader(String.valueOf(param.getKey()), String.valueOf(param.getValue()));
        }
        return getResult(httpGet);
    }

    public static String doPost(String url, Map<?, ?> params) throws UnsupportedEncodingException {
        HttpPost httpPost = new HttpPost(url);
        ArrayList<NameValuePair> pairs = covertParams2NVPS(params);
        httpPost.setEntity(new UrlEncodedFormEntity(pairs, UTF_8));
        return getResult(httpPost);
    }

    public static byte[] doPost(String url, String body) throws UnsupportedEncodingException {
        HttpPost httpPost = new HttpPost(url);
        HttpEntity httpEntity = new StringEntity(body, ContentType.APPLICATION_JSON);
        httpPost.setEntity(httpEntity);
        return getResult1(httpPost);
    }

    public static String doPost(String url, Map<?, ?> headers, Map<?, ?> params) throws UnsupportedEncodingException {
        HttpPost httpPost = new HttpPost(url);

        for (Map.Entry<?, ?> param : headers.entrySet()) {
            httpPost.addHeader(String.valueOf(param.getKey()), String.valueOf(param.getValue()));
        }

        ArrayList<NameValuePair> pairs = covertParams2NVPS(params);
        httpPost.setEntity(new UrlEncodedFormEntity(pairs, UTF_8));

        return getResult(httpPost);
    }

    public static String doPost(String url, Map<?, ?> headers, String data) throws UnsupportedEncodingException {
        HttpPost httpPost = new HttpPost(url);

        for (Map.Entry<?, ?> param : headers.entrySet()) {
            httpPost.addHeader(String.valueOf(param.getKey()), String.valueOf(param.getValue()));
        }
        StringEntity entity = new StringEntity(data, UTF_8);
        entity.setContentEncoding(UTF_8);
        entity.setContentType("application/json");
        httpPost.setEntity(entity);

        return getResult(httpPost);
    }

    private static ArrayList<NameValuePair> covertParams2NVPS(Map<?, ?> params) {
        ArrayList<NameValuePair> pairs = new ArrayList<NameValuePair>();
        for (Map.Entry<?, ?> param : params.entrySet()) {
            pairs.add(new BasicNameValuePair(String.valueOf(param.getKey()), String.valueOf(param.getValue())));
        }

        return pairs;
    }

    /**
     * 处理Http请求
     *
     * @param request
     * @return
     */
    private static String getResult(HttpRequestBase request) {
        CloseableHttpClient httpClient = getHttpClient();
        try {
            try(CloseableHttpResponse response = httpClient.execute(request)){
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    String result = EntityUtils.toString(entity);
                    response.close();
                    return result;
                }
            }
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return EMPTY_STR;
    }

    private static byte[] getResult1(HttpRequestBase request) {
        CloseableHttpClient httpClient = getHttpClient();
        try {
            try (CloseableHttpResponse response = httpClient.execute(request)){
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    try(InputStream inputStream = entity.getContent()){
                        ByteArrayOutputStream os = new ByteArrayOutputStream();
                        byte[] buff = new byte[100];
                        int rc = 0;
                        while ((rc = inputStream.read(buff, 0, 100)) > 0) {
                            os.write(buff, 0, rc);
                        }
                        return os.toByteArray();
                    }
                }
            }
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    private static String getResult2(HttpRequestBase request) {
        CloseableHttpClient httpClient = getHttpClient();
        try {
            try(CloseableHttpResponse response = httpClient.execute(request)){
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    try(InputStream inputStream = entity.getContent()){
                        ByteArrayOutputStream os = new ByteArrayOutputStream();
                        byte[] buff = new byte[100];
                        int rc = 0;
                        while ((rc = inputStream.read(buff, 0, 100)) > 0) {
                            os.write(buff, 0, rc);
                        }
                        Header firstHeader = response.getFirstHeader("content-type");
                        String value = "data:"+firstHeader.getValue()+";base64,";
                        return value + Base64.getEncoder().encodeToString(os.toByteArray());
                    }
                }
            }
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

}